# -*- coding: utf-8 -*-
import socket
import select
import errno
import struct
import logging

logger = logging.getLogger(__name__)


class ClientBase(object):
    NET_HEAD_LENGTH_SIZE = 4
    NET_HEAD_LENGTH_FORMAT = '<I'
    NET_CONNECTION_DATA = 1

    def __init__(self):
        super(ClientBase, self).__init__()
        self.socket = None
        self.event = []
        self._buffer = bytes()

    def connect(self, ip='localhost', port=2435):
        self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        self.socket.connect((ip, port))
        self.socket.setblocking(True)

    def set_blocking(self, is_block):
        self.socket.setblocking(is_block)

    def send(self, data):
        head = struct.pack(self.NET_HEAD_LENGTH_FORMAT, len(data))
        self.socket.send(head + data)

    def process(self):
        """ 每次从socket取到数据，应重新进行调用继续接受数据 """
        self._handle_recv()

    def _handle_recv(self):
        data = None
        try:
            data = self.socket.recv(1024)
            if not data:        # 当收到空数据时，应为socket端开
                self.close()
                return -1
        except socket.error as e:
            if e.errno not in (errno.EINPROGRESS, errno.EALREADY, errno.EWOULDBLOCK):
                self.close()
                return -1

        self._buffer = self._pack_events(self._buffer + data)

    def _pack_events(self, data):
        recv_len = len(data)
        curr_len = 0
        while True:
            if recv_len - curr_len < self.NET_HEAD_LENGTH_SIZE:
                return data[curr_len:]
            data_len = struct.unpack(self.NET_HEAD_LENGTH_FORMAT, data[curr_len: curr_len + self.NET_HEAD_LENGTH_SIZE])[0]
            if recv_len < curr_len + data_len + self.NET_HEAD_LENGTH_SIZE:
                return data[curr_len:]
            curr_len += self.NET_HEAD_LENGTH_SIZE
            self.event.append((self.NET_CONNECTION_DATA, data[curr_len:curr_len + data_len]))
            curr_len += data_len

    @property
    def has_events(self):
        if self.event:
            return True
        else:
            return False

    def get_next_event(self):
        return self.event.pop(0)

    def close(self):
        if self.socket:
            try:
                self.socket.close()
            except Exception as e:
                print(e)
            self.socket = None
